﻿// ....................................................................................................................
//	Author: Copyright (C) 2012 Ing. Marek Hubal
//	Email: hubal@acasoftware.org
// ....................................................................................................................

using System;

namespace core
{
    /// <summary>Trieda IUnrar</summary>
    public class IUnrar
    {
        #region Enumeracie
        public enum OpenMode
        {
            List = 0,
            Extract = 1
        }
        public enum RarError : uint
        {
            EndOfArchive = 10,
            InsufficientMemory = 11,
            BadData = 12,
            BadArchive = 13,
            UnknownFormat = 14,
            OpenError = 15,
            CreateError = 16,
            CloseError = 17,
            ReadError = 18,
            WriteError = 19,
            BufferTooSmall = 20,
            UnknownError = 21
        }
        public enum Operation : uint
        {
            Skip = 0,
            Test = 1,
            Extract = 2
        }
        public enum VolumeMessage : uint
        {
            Ask = 0,
            Notify = 1
        }
        [Flags]
        public enum ArchiveFlags : uint
        {
            Volume = 0x1,
            CommentPresent = 0x2,
            Lock = 0x4,
            SolidArchive = 0x8,
            NewNamingScheme = 0x10,
            AuthenticityPresent = 0x20,
            RecoveryRecordPresent = 0x40,
            EncryptedHeaders = 0x80,
            FirstVolume = 0x100
        }
        public enum CallbackMessages : uint
        {
            VolumeChange = 0,
            ProcessData = 1,
            NeedPassword = 2
        }
        #endregion
        #region Struktury
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
        public struct RARHeaderData
        {
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 260)]
            public string ArcName;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 260)]
            public string FileName;
            public uint Flags;
            public uint PackSize;
            public uint UnpSize;
            public uint HostOS;
            public uint FileCRC;
            public uint FileTime;
            public uint UnpVer;
            public uint Method;
            public uint FileAttr;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string CmtBuf;
            public uint CmtBufSize;
            public uint CmtSize;
            public uint CmtState;

            public void Initialize()
            {
                this.CmtBuf = new string((char)0, 65536);
                this.CmtBufSize = 65536;
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
        public struct RARHeaderDataEx
        {
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 512)]
            public string ArcName;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string ArcNameW;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 512)]
            public string FileName;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 1024)]
            public string FileNameW;
            public uint Flags;
            public uint PackSize;
            public uint PackSizeHigh;
            public uint UnpSize;
            public uint UnpSizeHigh;
            public uint HostOS;
            public uint FileCRC;
            public uint FileTime;
            public uint UnpVer;
            public uint Method;
            public uint FileAttr;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string CmtBuf;
            public uint CmtBufSize;
            public uint CmtSize;
            public uint CmtState;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 1024)]
            public uint[] Reserved;

            public void Initialize()
            {
                this.CmtBuf = new string((char)0, 65536);
                this.CmtBufSize = 65536;
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
        public struct RAROpenArchiveData
        {
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 260)]
            public string ArcName;
            public uint OpenMode;
            public uint OpenResult;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string CmtBuf;
            public uint CmtBufSize;
            public uint CmtSize;
            public uint CmtState;

            public void Initialize()
            {
                this.CmtBuf = new string((char)0, 65536);
                this.CmtBufSize = 65536;
            }
        }
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct RAROpenArchiveDataEx
        {
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string ArcName;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]
            public string ArcNameW;
            public uint OpenMode;
            public uint OpenResult;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)]
            public string CmtBuf;
            public uint CmtBufSize;
            public uint CmtSize;
            public uint CmtState;
            public uint Flags;
            [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 32)]
            public uint[] Reserved;

            public void Initialize()
            {
                this.CmtBuf = new string((char)0, 65536);
                this.CmtBufSize = 65536;
                this.Reserved = new uint[32];
            }
        }
        #endregion
        #region Funkcie
        [System.Runtime.InteropServices.DllImport("unrar.dll")]
		public static extern IntPtr RAROpenArchive(ref RAROpenArchiveData archiveData);
		[System.Runtime.InteropServices.DllImport("UNRAR.DLL")]
		public static extern IntPtr RAROpenArchiveEx(ref RAROpenArchiveDataEx archiveData);
		[System.Runtime.InteropServices.DllImport("unrar.dll")]
		public static extern int RARCloseArchive(IntPtr hArcData);
		[System.Runtime.InteropServices.DllImport("unrar.dll")]
        public static extern int RARReadHeader(IntPtr hArcData, ref RARHeaderData headerData);
		[System.Runtime.InteropServices.DllImport("unrar.dll")]
        public static extern int RARReadHeaderEx(IntPtr hArcData, ref RARHeaderDataEx headerData);
		[System.Runtime.InteropServices.DllImport("unrar.dll")]
        public static extern int RARProcessFile(IntPtr hArcData, int operation, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] string destPath, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] string destName);
		[System.Runtime.InteropServices.DllImport("unrar.dll")]
        public static extern void RARSetCallback(IntPtr hArcData, UNRARCallback callback, int userData);
		[System.Runtime.InteropServices.DllImport("unrar.dll")]
		public static extern void RARSetPassword(IntPtr hArcData, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password);
		
        public delegate int UNRARCallback(uint msg, int UserData, IntPtr p1, int p2);        
        #endregion
    }

    /// <summary>Trieda INodeList_RAR</summary>
    public class INodeList_RAR : INodeList
    {
        /// <summary>Trieda INodeComparer</summary>
        protected class INodeComparer : System.Collections.Generic.IComparer<INode>
        {
            protected delegate int OnCompare(INode N1, INode N2);
            protected OnCompare FCompareMethod; // Metoda porovnania

            /// <summary>Porovnanie podla nazvu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Asc(INode N1, INode N2)
            {
                return string.Compare(((INodeData_RAR_ITEM)N1.NodeData).RAR_ItemName, ((INodeData_RAR_ITEM)N2.NodeData).RAR_ItemName);
            }
            /// <summary>Porovnanie podla nazvu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_0_Desc(INode N1, INode N2)
            {
                return -string.Compare(((INodeData_RAR_ITEM)N1.NodeData).RAR_ItemName, ((INodeData_RAR_ITEM)N2.NodeData).RAR_ItemName);
            }
            /// <summary>Porovnanie podla pripony asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Asc(INode N1, INode N2)
            {
                int R = string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Asc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla pripony desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_1_Desc(INode N1, INode N2)
            {
                int R = -string.Compare(N1.Ext, N2.Ext);
                if (R == 0) return Compare_0_Desc(N1, N2);
                else return R;
            }
            /// <summary>Porovnanie podla velkosti asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Asc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Asc(N1, N2);
                return N1.Size > N2.Size ? 1 : -1;
            }
            /// <summary>Porovnanie podla velkosti desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_2_Desc(INode N1, INode N2)
            {
                if (N1.Size == N2.Size) return Compare_0_Desc(N1, N2);
                return N1.Size > N2.Size ? -1 : 1;
            }
            /// <summary>Porovnanie podla komprimovanej velkosti</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_3_Asc(INode N1, INode N2)
            {
                if (((INodeData_RAR_ITEM)N1.NodeData).RAR_CompressedSize == ((INodeData_RAR_ITEM)N2.NodeData).RAR_CompressedSize) return Compare_0_Asc(N1, N2);
                return ((INodeData_RAR_ITEM)N1.NodeData).RAR_CompressedSize > ((INodeData_RAR_ITEM)N2.NodeData).RAR_CompressedSize ? 1 : -1;
            }
            /// <summary>Porovnanie podla komprimovanej velkosti</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_3_Desc(INode N1, INode N2)
            {
                if (((INodeData_RAR_ITEM)N1.NodeData).RAR_CompressedSize == ((INodeData_RAR_ITEM)N2.NodeData).RAR_CompressedSize) return Compare_0_Asc(N1, N2);
                return ((INodeData_RAR_ITEM)N1.NodeData).RAR_CompressedSize > ((INodeData_RAR_ITEM)N2.NodeData).RAR_CompressedSize ? -1 : 1;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu asc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Asc(INode N1, INode N2)
            {
                int R = N1.DLastModify.CompareTo(N2.DLastModify);
                if (R == 0) return Compare_0_Asc(N1, N2);
                return R;
            }
            /// <summary>Porovnanie podla datumu posledneho zapisu desc</summary>
            /// <param name="N1">node 1</param>
            /// <param name="N2">node 2</param>
            /// <returns>vysledok porovnania</returns>
            protected int Compare_4_Desc(INode N1, INode N2)
            {
                int R = -N1.DLastModify.CompareTo(N2.DLastModify); ;
                if (R == 0) return Compare_0_Desc(N1, N2);
                return R;
            }

            /// <summary>Konstruktor</summary>
            /// <param name="pCol">triediaci stlpec</param>
            /// <param name="pDirection">smer</param>
            public INodeComparer(int pCol, bool pDirection)
            {
                switch (pCol)
                {
                    case 4: if (pDirection) FCompareMethod = Compare_4_Asc; else FCompareMethod = Compare_4_Desc; break;
                    case 3: if (pDirection) FCompareMethod = Compare_3_Asc; else FCompareMethod = Compare_3_Desc; break;
                    case 2: if (pDirection) FCompareMethod = Compare_2_Asc; else FCompareMethod = Compare_2_Desc; break;
                    case 1: if (pDirection) FCompareMethod = Compare_1_Asc; else FCompareMethod = Compare_1_Desc; break;
                    default: if (pDirection) FCompareMethod = Compare_0_Asc; else FCompareMethod = Compare_0_Desc; break;
                }
            }

            /// <summary>Compare metoda</summary>
            /// <param name="x">objekt 1</param>
            /// <param name="y">objekt 2</param>
            /// <returns>vysledok porovnania</returns>
            int System.Collections.Generic.IComparer<INode>.Compare(INode x, INode y)
            {
                return FCompareMethod(x, y); // Volam porovnavaciu metodu
            }
        }

        protected string FBaseArchiveFileName; // Nazov archivu
        protected string FRelativePath; // Relativna cesta
        protected string FPassword; // Heslo pre spracovanie

        protected IntPtr FExpand_ArchiveHandle; // Handle archivu pri expandovani
        protected IUnrar.UNRARCallback FExpand_CallbackRoutine = null; // Callback rutina
        protected IUnrar.RARHeaderDataEx FExpand_HeaderDataEx; // Struktura pre nacitanie hlavicky zaznamu
        protected System.Collections.Generic.List<INode> FExpand_Dirs;
        protected System.Collections.Generic.List<INode> FExpand_Files;
        protected int FExpand_TotalCount; // Pocitadlo vsetkych poloziek pri expande
        protected IFileExplorer_ProgressForm_TestArchive FTest_ProgressForm; // Progress formular pri procese testovania

        protected IntPtr FExtract_ArchiveHandle; // Handle archivu pri expandovani
        protected INode FExtract_CurrentItem; // Node pre aktualne spracovany zaznam
        protected System.Collections.Generic.List<string> FExtract_ListOfItems; // Zoznam poloziek na extrahovanie
        protected string FExtract_ListOfItemsRoot; // Spolocny zaciatok vsetkych poloziek
        protected IUnrar.RARHeaderDataEx FExtract_HeaderDataEx;
        protected IFileExplorer_ProgressForm_ExtractArchive FExtract_ProgressForm; // Progress formular pri procese testovania
        protected IUnrar.UNRARCallback FExtract_CallbackRoutine = null; // Callback rutina
        protected INodeList FExtract_DestList; // Zoznam cieloveho umiestnenia suboru

        /// <summary>Konstruktor</summary>
        /// <param name="pArchiveFileName">nazov suboru archivu</param>
        /// <param name="pRelativePath">relativna cesta v archive</param>
        public INodeList_RAR(string pArchiveFileName = "", string pRelativePath = "")
        {
            ID = INodeList.NODE_LIST_ID_RAR_ARCHIVE;
            FColsCount = 6;
            FEnableVisibilityMask = 0x3e; FDefVisibilityMask = 0x3f;
            FThreadExpandAvailable = true;
            FBaseArchiveFileName = pArchiveFileName; FRelativePath = pRelativePath;
            FExpand_ArchiveHandle = IntPtr.Zero;
            FPassword = null;
        }

        /// <summary>Callback funkcia expandovania</summary>
        /// <param name="msg">sprava</param>
        /// <param name="UserData">uzivatelsky udaj</param>
        /// <param name="p1">parameter1</param>
        /// <param name="p2">parameter2</param>
        /// <returns>navratovy kod</returns>
        protected int Expand_RARCallback(uint msg, int UserData, IntPtr p1, int p2)
        {
            switch ((IUnrar.CallbackMessages)msg)
            {
                case IUnrar.CallbackMessages.VolumeChange:
                    {
                        string FileName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(p1); // Ocakavane meno
                        if (IFileSystem.GetObjectType(FileName) != IFileSystem.OBJECT_TYPE_FILE) return -1; // Neexistuje?
                        return 1; // Existuje
                    }
                case IUnrar.CallbackMessages.NeedPassword:
                    {
                        string P = ""; // Poziadam o heslo
                        if (FPassword != null)
                        {
                            P = FPassword;
                        }
                        else
                        {
                            IApp.App.WaitCursor = false;
                            if (!IApp.ShowEditor_String(lang.NODE_LIST_RAR_ARCHIVE_TEXT_13, lang.NODE_LIST_RAR_ARCHIVE_TEXT_12, ref P, -1, true))
                            {
                                IApp.App.WaitCursor = true;
                                return -1;
                            }
                            IApp.App.WaitCursor = true;
                        }
                        // Skopirujem do unmanaged pamate
                        for (int i = 0; (i < P.Length) && (i < p2); i++) System.Runtime.InteropServices.Marshal.WriteByte(p1, i, (byte)P[i]);
                        System.Runtime.InteropServices.Marshal.WriteByte(p1, P.Length, (byte)0);
                        return 1;
                    }
            }
            return -1;
        }
        /// <summary>Callback funkcia expandovania</summary>
        /// <param name="msg">sprava</param>
        /// <param name="UserData">uzivatelsky udaj</param>
        /// <param name="p1">parameter1</param>
        /// <param name="p2">parameter2</param>
        /// <returns>navratovy kod</returns>
        protected int Test_RARCallback(uint msg, int UserData, IntPtr p1, int p2)
        {
            switch ((IUnrar.CallbackMessages)msg)
            {
                case IUnrar.CallbackMessages.VolumeChange:
                    {
                        string FileName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(p1); // Ocakavane meno
                        if ((IUnrar.VolumeMessage)p2 == IUnrar.VolumeMessage.Notify)
                        {
                            if (FTest_ProgressForm != null) FTest_ProgressForm.StartArchiveVolume(FileName, "RAR");
                            return 1; // Notifikacia?
                        }

                        if (IFileSystem.GetObjectType(FileName) != IFileSystem.OBJECT_TYPE_FILE) return -1;
                        return 0; // Existuje
                    }
                case IUnrar.CallbackMessages.NeedPassword:
                    {
                        string P = IApp.GlobalData.GetPassword(PasswordCacheID); // Poziadam o heslo
                        if (P == null)
                        {
                            P = "";
                            if (!IApp.ShowEditor_String(lang.NODE_LIST_RAR_ARCHIVE_TEXT_13, lang.NODE_LIST_RAR_ARCHIVE_TEXT_12, ref P, -1, true, null, null, true))
                            {
                                return -1;
                            }
                        }

                        // Skopirujem do unmanaged pamate
                        for (int i = 0; (i < P.Length) && (i < p2); i++) System.Runtime.InteropServices.Marshal.WriteByte(p1, i, (byte)P[i]);
                        System.Runtime.InteropServices.Marshal.WriteByte(p1, P.Length, (byte)0);
                        return 1;
                    }
                case IUnrar.CallbackMessages.ProcessData:
                    {
                        return ((FTest_ProgressForm != null) && (FTest_ProgressForm.WaitForTerminate.BoolValue)) ? -1 : 1;
                    }
            }
            return -1;
        }
        /// <summary>Callback funkcia expandovania</summary>
        /// <param name="msg">sprava</param>
        /// <param name="UserData">uzivatelsky udaj</param>
        /// <param name="p1">parameter1</param>
        /// <param name="p2">parameter2</param>
        /// <returns>navratovy kod</returns>
        protected int Extract_RARCallback(uint msg, int UserData, IntPtr p1, int p2)
        {
            switch ((IUnrar.CallbackMessages)msg)
            {
                case IUnrar.CallbackMessages.VolumeChange:
                    {
                        string FileName = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(p1); // Ocakavane meno
                        if ((IUnrar.VolumeMessage)p2 == IUnrar.VolumeMessage.Notify)
                        {
                            if (FTest_ProgressForm != null) FTest_ProgressForm.StartArchiveVolume(FileName, "RAR");
                            return 1; // Notifikacia?
                        }

                        if (IFileSystem.GetObjectType(FileName) != IFileSystem.OBJECT_TYPE_FILE) return -1;
                        return 0; // Existuje
                    }
                case IUnrar.CallbackMessages.NeedPassword:
                    {
                        string P = IApp.GlobalData.GetPassword(PasswordCacheID); // Poziadam o heslo
                        if (P == null)
                        {
                            if (!IApp.ShowEditor_String(lang.NODE_LIST_RAR_ARCHIVE_TEXT_13, lang.NODE_LIST_RAR_ARCHIVE_TEXT_12, ref P, -1, true, null, null, true))
                            {
                                return -1;
                            }
                        }

                        // Skopirujem do unmanaged pamate
                        for (int i = 0; (i < P.Length) && (i < p2); i++) System.Runtime.InteropServices.Marshal.WriteByte(p1, i, (byte)P[i]);
                        System.Runtime.InteropServices.Marshal.WriteByte(p1, P.Length, (byte)0);
                        return 1;
                    }
                case IUnrar.CallbackMessages.ProcessData:
                    {
                        int C = p2;
                        while (true)
                        {
                            int R = FExtract_DestList.CopyMode_WriteFile(p1, 0, C); // Zapisem
                            if (R == 0) break;
                            switch (R)
                            {
                                case IFileSystem.FS_ERROR_NOT_ENOUGH_SPACE: // Plny disk?
                                    {
                                        R = 0;
                                        if (!FExtract_ProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_24_4_25, CopyMode_MakeSourceFullPath(ExtractMode_CurrentName())), lang.FILE_EXPLORER_TEXT_24_4_26, lang.FILE_EXPLORER_TEXT_24_4_27, ref R))
                                        {
                                            if (FExtract_ProgressForm != null) FExtract_ProgressForm.AddTransferredDataSize(-1); // Koniec prenosu
                                            FExtract_DestList.CopyMode_CloseWriteFile(true); // Uzatvorim subor
                                            if (FExtract_ProgressForm != null) FExtract_ProgressForm.AddFile(true); // Zaradim subor
                                            return -1; // Test ukoncenia
                                        }
                                    } break;
                                default:
                                    {
                                        return -1;
                                    }
                            }
                        }

                        if (FExtract_ProgressForm != null) FExtract_ProgressForm.AddTransferredDataSize((long)C);
                        return 1;
                    }
            }
            return -1;
        }

        /// <summary>Property: CacheID</summary>
        public override string CacheID
        {
            get
            {
                return FBaseArchiveFileName.ToLower();
            }
        }

        /// <summary>Zapis node do cache</summary>
        /// <param name="pNode">objekt</param>
        protected override void WriteNodeToCache(INode pNode)
        {
            if (!IsWriteCacheReady) return; // Ziadna cache?

            FCacheWriter.Write(pNode.ID);
            FCacheWriter.Write(((INodeData_RAR_ITEM)pNode.NodeData).RAR_Attributes);
            FCacheWriter.Write(((INodeData_RAR_ITEM)pNode.NodeData).RAR_CompressedSize);
            FCacheWriter.Write(((INodeData_RAR_ITEM)pNode.NodeData).RAR_CRC);
            FCacheWriter.Write(((INodeData_RAR_ITEM)pNode.NodeData).RAR_ItemName);
            FCacheWriter.Write(((INodeData_RAR_ITEM)pNode.NodeData).RAR_ModifyDate);
            FCacheWriter.Write(((INodeData_RAR_ITEM)pNode.NodeData).RAR_OriginalSize);
        }
        /// <summary>Nacitanie node z cache</summary>
        /// <returns>objekt alebo null pre koniec</returns>
        protected override bool ReadNodeFromCache(INode Result)
        {
            if (!IsReadCacheReady) return false;
            try
            {
                Result.ID = FCacheReader.ReadInt32(); // Nacitam
                Result.NodeData = new INodeData_RAR_ITEM();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_Attributes = FCacheReader.ReadUInt32();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_CompressedSize = FCacheReader.ReadInt64();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_CRC = FCacheReader.ReadUInt32();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_ItemName = FCacheReader.ReadString();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_ModifyDate = FCacheReader.ReadUInt32();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_OriginalSize = FCacheReader.ReadInt64();
                return true; // Vsetko OK
            }
            catch
            {
                return false;
            }
        }
        /// <summary>Otvorenie cache pre citanie</summary>
        /// <returns>true / false</returns>
        public override bool BeginReadCache()
        {
            return false;
        }

        /// <summary>Ziskanie nazvu stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>nazov alebo prazdny retazec</returns>
        public override string GetColumnName(int pIndex)
        {
            switch (pIndex)
            {
                case 0: return lang.NODE_LIST_RAR_ARCHIVE_TEXT_1;
                case 1: return lang.NODE_LIST_RAR_ARCHIVE_TEXT_2;
                case 2: return lang.NODE_LIST_RAR_ARCHIVE_TEXT_3;
                case 3: return lang.NODE_LIST_RAR_ARCHIVE_TEXT_4;
                case 4: return lang.NODE_LIST_RAR_ARCHIVE_TEXT_5;
                case 5: return lang.NODE_LIST_RAR_ARCHIVE_TEXT_6;
                default: return "";
            }
        }
        /// <summary>Ziskanie zarovnania stlpca</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>zarovnanie</returns>
        public override System.Windows.Forms.HorizontalAlignment GetColumnAlignment(int pIndex)
        {
            switch (pIndex)
            {
                case 2:
                case 3:
                    return System.Windows.Forms.HorizontalAlignment.Right;
                case 4:
                case 5:
                    return System.Windows.Forms.HorizontalAlignment.Center;
                default: return System.Windows.Forms.HorizontalAlignment.Left;
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string CurrentPath
        {
            get
            {
                return IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath);
            }
        }
        /// <summary>Property: KeyValue</summary>
        public override string KeyValue
        {
            get
            {
                if (FRelativePath == "") return IFileSystem.ExtractName(FBaseArchiveFileName).ToLower();
                return IFileSystem.ExtractName(IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath)).ToLower();
            }
        }
        /// <summary>Property: CurrentPath</summary>
        public override string ParentPath
        {
            get
            {
                if (FRelativePath == "") return IFileSystem.ExtractPath(FBaseArchiveFileName);
                int I = FRelativePath.LastIndexOf('\\');
                if (I == -1) return FBaseArchiveFileName;
                return IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath.Substring(0, I));
            }
        }
        /// <summary>Test ci sa node moze expandovat</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanNodeExpand(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return false; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_RAR_ITEM:
                    {
                        return N.IsDirectory;
                    }
                default: return false;
            }
        }
        /// <summary>Ziskanie expandovacej cesty node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>cesta</returns>
        public override string GetNodeExpandPath(int pIndex)
        {
            INode N = this[pIndex];
            if (N == null) return ""; // Ziskam platny node

            switch (N.ID)
            {
                case INode.NODE_ID_RAR_ITEM: return IFileSystem.AppendToPath(IFileSystem.CreateFullArchivePath(FBaseArchiveFileName, FRelativePath), ((INodeData_RAR_ITEM)N.NodeData).RAR_ItemName);
                default: return "";
            }
        }
        /// <summary>Property: DeviceRootPath</summary>
        public override string DeviceRootPath
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }
        /// <summary>Property: CanSort</summary>
        public override bool CanSort
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test ci je mozne podla zadaneho stlpca triedit</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool IsSortColumn(int pIndex)
        {
            switch (pIndex)
            {
                case 5:
                    return false;
                default: return true;
            }
        }
        /// <summary>Property: CanSelect</summary>
        public override bool CanSelect
        {
            get
            {
                return true;
            }
        }
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        /// <summary>Test moznosti oznacenia node</summary>
        /// <param name="pIndex">pozicia</param>
        /// <returns>true / false</returns>
        public override bool CanSelectNode(INode pNode)
        {
            if (pNode == null) return false; // Ziskam platny node

            switch (pNode.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: Test ci je list archivom</summary>
        public override bool IsArchive
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: ArchiveName</summary>
        public override string ArchiveName
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }
        /// <summary>Property: IsCopySource</summary>
        public override bool IsCopySource
        {
            get
            {
                return true;
            }
        }
        /// <summary>Property: IsCopySourceItem</summary>
        public override bool IsCopySourceItem(int pIndex)
        {
            if (!IsCopySource) return false; // Test celku
            INode N = this[pIndex];
            if (N == null) return false; // Neplatny node?
            switch (N.ID)
            {
                case INode.NODE_ID_BACK_ITEM: return false;
                default: return true;
            }
        }
        /// <summary>Property: NeedPassword</summary>
        public override bool NeedPasswordForExpand
        {
            get
            {
                IUnrar.RAROpenArchiveDataEx Str = new IUnrar.RAROpenArchiveDataEx(); // Vyplnim strukturu
                Str.Initialize();
                Str.ArcName = FBaseArchiveFileName + "\0";
                Str.ArcNameW = FBaseArchiveFileName + "\0";
                Str.OpenMode = (uint)IUnrar.OpenMode.List;
                Str.CmtBuf = null;
                Str.CmtBufSize = 0;

                IntPtr Handle = IUnrar.RAROpenArchiveEx(ref Str); // Otvorim archiv
                if (Str.OpenResult != 0) return false;
                IUnrar.RARCloseArchive(Handle); // Uzatvorim archiv
                if ((Str.Flags & 0x0080) == 0) return false; // Netreba heslo
                FPassword = IApp.GlobalData.GetPassword(PasswordCacheID); // Ziskam heslo
                return FPassword == null; // Ak zlyhalo ziskanie hesla z cache tak poviem ze heslo potrebujem
                /*
                if ((Str.Flags & 0x0080) != 0)
                {
                    IUnrar.RARCloseArchive(Handle); // Uzatvorim archiv
                    return true;
                }

                IUnrar.RARHeaderDataEx HeaderDataEx = new IUnrar.RARHeaderDataEx(); HeaderDataEx.Initialize(); // Inicializujem
                int result = IUnrar.RARReadHeaderEx(Handle, ref HeaderDataEx);
                if (result != 0)
                {
                    IUnrar.RARCloseArchive(Handle); // Uzatvorim archiv
                    return false;
                }

                bool B = (HeaderDataEx.Flags & 0x04) != 0;
                IUnrar.RARCloseArchive(Handle); // Uzatvorim archiv

                return B;
                 */
            }
        }
        /// <summary>Nastavenie hesla pre spracovanie</summary>
        /// <param name="pValue">hodnota</param>
        public override void SetPassword(string pValue)
        {
            FPassword = pValue;
            IApp.GlobalData.SavePassword(PasswordCacheID, pValue);
        }
        /// <summary>Property: BasePath</summary>
        public override string BasePath
        {
            get
            {
                return FBaseArchiveFileName;
            }
        }

        /// <summary>Zaciatok expandovania obsahu</summary>
        /// <param name="pFilter">objekt filtra</param>
        /// <returns>0 alebo kod chyby</returns>
        public override int BeginExpand(INodeFilters pFilter = null)
        {
            FState = 1; // Nastavim stav expandovania
            try
            {
                IUnrar.RAROpenArchiveDataEx Str = new IUnrar.RAROpenArchiveDataEx(); // Vyplnim strukturu
                Str.Initialize();
                Str.ArcName = FBaseArchiveFileName + "\0";
                Str.ArcNameW = FBaseArchiveFileName + "\0";
                Str.OpenMode = (uint)IUnrar.OpenMode.List;
                Str.CmtBuf = null;
                Str.CmtBufSize = 0;

                FExpand_ArchiveHandle = IUnrar.RAROpenArchiveEx(ref Str); // Otvorim archiv
                if (Str.OpenResult != 0) // Chyba?
                {
                    FExpand_ArchiveHandle = IntPtr.Zero;
                    return -1;
                }

                FExpand_CallbackRoutine = new IUnrar.UNRARCallback(Expand_RARCallback);
                IUnrar.RARSetCallback(FExpand_ArchiveHandle, FExpand_CallbackRoutine, this.GetHashCode()); // Nastavim callback funkciu
                
                FExpand_HeaderDataEx = new IUnrar.RARHeaderDataEx(); FExpand_HeaderDataEx.Initialize(); // Inicializujem

                FExpand_Dirs = new System.Collections.Generic.List<INode>(); FExpand_Files = new System.Collections.Generic.List<INode>(); // Polia pre subory a priecinky
                FExpand_TotalCount = 0;

                return 0; // Vsetko OK
            }
            catch
            {
                return -1; // Nie je mozne otvorit archiv
            }
        }
        /// <summary>Uzatvorenie aktualneho expandu</summary>
        public override void CloseExpand()
        {
            if (FExpand_ArchiveHandle != IntPtr.Zero)
            {
                // Zaradim do zoznamu
                for (int i = 0; i < FExpand_Dirs.Count; i++) AddNode(FExpand_Dirs[i]);
                for (int i = 0; i < FExpand_Files.Count; i++) AddNode(FExpand_Files[i]);

                FExpand_Dirs.Clear(); FExpand_Dirs = null;
                FExpand_Files.Clear(); FExpand_Files = null;

                IUnrar.RARCloseArchive(FExpand_ArchiveHandle);
                FExpand_ArchiveHandle = IntPtr.Zero;
            }
            FState = 0; // Nastavim normalny stav
        }
        /// <summary>Expandovanie dalsieho zaznamu</summary>
        /// <param name="Result">ulozeny obsah najdeneho zaznamu alebo null ak sa ma zaznam pripojit do zoznamu</param>
        /// <returns>0 - ziaden dalsi zaznam, 1 - najdeny zaznam alebo kod chyby</returns>
        public override int ExpandNext(INodeFilters pFilter = null, INode Result = null)
        {
            try {
                if (FItems.Count == 0) // Nepridany back node?
                {
                    if (Result == null)
                    {
                        INode N2 = new INode(); N2.ID = INode.NODE_ID_BACK_ITEM; AddNode(N2); // Vytvorim prvy back item node
                    }
                }

                string RelP = FRelativePath + "\\";
                string RelName = "";
                INode N = Result == null ? new INode() : Result;

                if (IsReadCacheReady) // Citanie z cache?
                {
                    while (true)
                    {
                        if (!ReadNodeFromCache(N))
                        {
                            if (Result == null) N.Dispose();
                            return 0;
                        }
                        WriteNodeToCache(N);

                        RelName = ((INodeData_RAR_ITEM)N.NodeData).RAR_ItemName;
                        FExpand_TotalCount++;

                        if (FRelativePath != "")
                        {
                            if (string.Compare(RelP, 0, RelName, 0, RelP.Length, false) != 0)
                            {
                                if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_RAR_ARCHIVE_TEXT_11, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                                continue;
                            }
                            RelName = RelName.Substring(RelP.Length);
                        }
                        if (RelName.IndexOf('\\') != -1)
                        {
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_RAR_ARCHIVE_TEXT_11, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                            continue;
                        }
                        ((INodeData_RAR_ITEM)N.NodeData).RAR_ItemName = RelName;
                        if (Result == null)
                        {
                            if (N.IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_RAR_ARCHIVE_TEXT_11, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                        }
                        FCachedContent = true;
                        return 1;
                    }
                }

                while (true)
                {
                    int result = IUnrar.RARReadHeaderEx(FExpand_ArchiveHandle, ref FExpand_HeaderDataEx);
                    if (result == (int)IUnrar.RarError.EndOfArchive)
                    {
                        if (Result == null) N.Dispose();
                        return 0; // Koniec archivu?
                    }
                    if (result == (int)IUnrar.RarError.BadData)
                    {
                        if (FPassword != null) IApp.GlobalData.SavePassword(PasswordCacheID, null);
                        if (Result == null) N.Dispose();
                        return -1; // Koniec archivu?
                    }
                    if (result != 0)
                    {
                        if (Result == null) N.Dispose();
                        return -1; // Chyba
                    }

                    if (IUnrar.RARProcessFile(FExpand_ArchiveHandle, (int)IUnrar.Operation.Skip, string.Empty, string.Empty) != 0) return -1;

                    RelName = FExpand_HeaderDataEx.FileNameW.ToString();
                    N.ID = INode.NODE_ID_RAR_ITEM;
                    N.NodeData = new INodeData_RAR_ITEM();
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_Attributes = FExpand_HeaderDataEx.FileAttr;
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_OriginalSize = FExpand_HeaderDataEx.UnpSizeHigh; ((INodeData_RAR_ITEM)N.NodeData).RAR_OriginalSize <<= 32; ((INodeData_RAR_ITEM)N.NodeData).RAR_OriginalSize += FExpand_HeaderDataEx.UnpSize;
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_CompressedSize = FExpand_HeaderDataEx.PackSizeHigh; ((INodeData_RAR_ITEM)N.NodeData).RAR_CompressedSize <<= 32; ((INodeData_RAR_ITEM)N.NodeData).RAR_CompressedSize += FExpand_HeaderDataEx.PackSize;
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_CRC = FExpand_HeaderDataEx.FileCRC;
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_ModifyDate = FExpand_HeaderDataEx.FileTime;
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_ItemName = RelName;
                    WriteNodeToCache(N); // Zapisem do cache

                    FExpand_TotalCount++;
                    if (FRelativePath != "")
                    {
                        if (string.Compare(RelP, 0, RelName, 0, RelP.Length, false) != 0)
                        {
                            if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_RAR_ARCHIVE_TEXT_11, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                            continue;
                        }
                        RelName = RelName.Substring(RelP.Length);
                    }
                    if (RelName.IndexOf('\\') != -1)
                    {
                        if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_RAR_ARCHIVE_TEXT_11, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);
                        continue;
                    }
                    ((INodeData_RAR_ITEM)N.NodeData).RAR_ItemName = RelName;
                    break;
                }

                if (Result == null)
                {
                    if (N.IsDirectory) FExpand_Dirs.Add(N); else FExpand_Files.Add(N);
                }
                if (ProgressMessage != null) ProgressMessage.StringValue = string.Format(lang.NODE_LIST_RAR_ARCHIVE_TEXT_11, FExpand_Dirs.Count + FExpand_Files.Count, FExpand_TotalCount);

                return 1;
            }
            catch
            {
                return -1;
            }
        }

        /// <summary>Vytvorenie textov pre zobrazenie</summary>
        /// <param name="pNode">objekt node</param>
        public override void CreateDisplayStrings(INode pNode)
        {
            if (pNode.DisplayStrings != null) return; // Uz su vytvorenie?

            pNode.DisplayStrings = new string[ColsCount]; // Alokujem retazec
            switch (pNode.ID) // Podla typu node
            {
                case INode.NODE_ID_BACK_ITEM:
                    {
                        pNode.DisplayStrings[0] = ICore.BoundString("[", "..", "]", IApp.Settings.FileExplorer_DirsInBraces);
                        pNode.DisplayStrings[2] = FRelativePath == "" ? lang.NODE_LIST_RAR_ARCHIVE_TEXT_7 : lang.NODE_LIST_RAR_ARCHIVE_TEXT_8;
                        pNode.DefaultImageIndex = -1;
                    } break;
                case INode.NODE_ID_RAR_ITEM:
                    {
                        if (pNode.IsDirectory)
                        {
                            pNode.DisplayStrings[0] = pNode.Name; // Len nazov
                            if (pNode.ValidSize) pNode.DisplayStrings[2] = ICore.Size2String((ulong)pNode.Size, IApp.Settings.FileExplorer_DisplaySizeMode);
                            else pNode.DisplayStrings[2] = lang.NODE_LIST_RAR_ARCHIVE_TEXT_9;
                            pNode.DefaultImageIndex = 0;
                        }
                        else
                        {
                            pNode.DisplayStrings[0] = pNode.NameOnly; // Len nazov
                            if (pNode.DisplayStrings[0] == "") pNode.DisplayStrings[0] = pNode.Name; else pNode.DisplayStrings[1] = pNode.Ext; // Pripona
                            pNode.DisplayStrings[2] = ICore.Size2String((ulong)((INodeData_RAR_ITEM)pNode.NodeData).RAR_OriginalSize, IApp.Settings.FileExplorer_DisplaySizeMode); // Velkost
                            pNode.DisplayStrings[3] = ICore.Size2String((ulong)((INodeData_RAR_ITEM)pNode.NodeData).RAR_CompressedSize, IApp.Settings.FileExplorer_DisplaySizeMode); // Komprimovana velkost
                            pNode.DisplayStrings[4] = ICore.DateTime2Str(pNode.DLastModify);
                            pNode.DisplayStrings[5] = ((INodeData_RAR_ITEM)pNode.NodeData).RAR_CRC.ToString("X8");
                            pNode.DefaultImageIndex = 1;
                        }
                    } break;
            }
        }
        /// <summary>Triedenie obsahu zoznamu</summary>
        /// <param name="pColumn">stlpec</param>
        /// <param name="pAsc">smer</param>
        public override void Sort(int pColumn, bool pAsc)
        {
            int S = IsBackNode(0) ? 1 : 0; // Urcim zaciatok
            if (DirsCount > 1)
            {
                FItems.Sort(S, DirsCount, new INodeComparer(0, pAsc));
            }
            if (FilesCount > 1)
            {
                FItems.Sort(S + DirsCount, FilesCount, new INodeComparer(pColumn, pAsc));
            }
        }
        /// <summary>Vytvorenie klonu zoznamu</summary>
        /// <returns>objekt zoznamu</returns>
        public override INodeList CloneList()
        {
            return new INodeList_RAR(FBaseArchiveFileName, FRelativePath);
        }

        /// <summary>Nastavenie zoznamu do modu zdroja extrahovania</summary>
        /// <param name="pItemsToExtract">polozky na extrahovanie</param>
        /// <param name="pProgressForm">progress formular</param>
        public override void BeginSourceExtractMode(System.Collections.Generic.List<string> pItemsToExtract = null, IFileExplorer_ProgressForm_ExtractArchive pProgressForm = null)
        {
            FExtract_ArchiveHandle = IntPtr.Zero;
            FExtract_CurrentItem = new INode();
            CopyMode_NativeDataBuffer = new byte[MAX_COPY_BUFFER_SIZE];

            if (pItemsToExtract == null) FExtract_ListOfItems = null;
            else
            {
                FExtract_ListOfItemsRoot = null;
                FExtract_ListOfItems = new System.Collections.Generic.List<string>();
                foreach (string S in pItemsToExtract) // Vytvorim relativne cesty
                {
                    int I = S.LastIndexOf(":\\");
                    if (I != -1)
                    {
                        string S1 = S.Substring(I + 2);
                        FExtract_ListOfItems.Add(S1);
                        if (FExtract_ListOfItemsRoot == null) FExtract_ListOfItemsRoot = S1;
                        else
                        {
                            if (FExtract_ListOfItemsRoot.Length > 0)
                            {
                                int i;
                                for (i = 0; i < FExtract_ListOfItemsRoot.Length; i++)
                                {
                                    if (i >= S1.Length) break;
                                    if (char.ToLower(FExtract_ListOfItemsRoot[i]) != char.ToLower(S1[i])) break;
                                }
                                if (i != FExtract_ListOfItemsRoot.Length) FExtract_ListOfItemsRoot = i == 0 ? "" : FExtract_ListOfItemsRoot.Substring(0, i);
                            }
                        }
                    }
                }
                if (string.IsNullOrEmpty(FExtract_ListOfItemsRoot)) FExtract_ListOfItemsRoot = "";
                else
                {
                    int I = FExtract_ListOfItemsRoot.LastIndexOf('\\');
                    FExtract_ListOfItemsRoot = I == -1 ? "" : FExtract_ListOfItemsRoot.Substring(0, I + 1);
                }
                FExtractMode_ItemsToExpandList = new System.Collections.Generic.Dictionary<string, int>(); // Vytvorim cache poloziek
                foreach (string FN in pItemsToExtract) FExtractMode_ItemsToExpandList.Add(FN.Substring(FBaseArchiveFileName.Length + 2).ToLower(), 0);
            }
        }
        /// <summary>Uzatvorenie modu extrahovania</summary>
        public override void CloseExtractMode()
        {
            if (FExtract_ArchiveHandle != IntPtr.Zero) IUnrar.RARCloseArchive(FExtract_ArchiveHandle); // Uzatvorim
            FExtract_CurrentItem = (INode)ICore.DisposeObject(FExtract_CurrentItem);
            CopyMode_NativeDataBuffer = null;
            FExtract_ArchiveHandle = IntPtr.Zero;
        }
        /// <summary>Ziskanie dalsieho zaznamu na extrahovanie</summary>
        /// <param name="Result">vysledne data</param>
        /// <returns>0 - koniec, 1 - platny zaznam, alebo kod chyby</returns>
        public override int ExtractMode_GetNextSourceItem(INode Result)
        {
            try
            {
                if (FExtract_ArchiveHandle == IntPtr.Zero)
                {
                    IUnrar.RAROpenArchiveDataEx Str = new IUnrar.RAROpenArchiveDataEx(); // Vyplnim strukturu
                    Str.Initialize();
                    Str.ArcName = FBaseArchiveFileName + "\0";
                    Str.ArcNameW = FBaseArchiveFileName + "\0";
                    Str.OpenMode = (uint)IUnrar.OpenMode.Extract;
                    Str.CmtBuf = null;
                    Str.CmtBufSize = 0;

                    FExtract_ArchiveHandle = IUnrar.RAROpenArchiveEx(ref Str); // Otvorim archiv
                    if (Str.OpenResult != 0) // Chyba?
                    {
                        FExtract_ArchiveHandle = IntPtr.Zero;
                        return -1;
                    }

                    FExtract_CallbackRoutine = new IUnrar.UNRARCallback(Extract_RARCallback);
                    IUnrar.RARSetCallback(FExtract_ArchiveHandle, FExtract_CallbackRoutine, this.GetHashCode()); // Nastavim callback funkciu
                
                    FExtract_HeaderDataEx = new IUnrar.RARHeaderDataEx(); FExtract_HeaderDataEx.Initialize(); // Inicializujem
                }

                int result = IUnrar.RARReadHeaderEx(FExtract_ArchiveHandle, ref FExtract_HeaderDataEx);
                if (result == (int)IUnrar.RarError.EndOfArchive)
                {
                    return 0; // Koniec archivu?
                }
                if (result != 0)
                {
                    return IFileSystem.FS_ERROR_UNKNOWN; // Chyba
                }

                FExtract_CurrentItem.ID = INode.NODE_ID_RAR_ITEM;
                FExtract_CurrentItem.NodeData = new INodeData_RAR_ITEM();
                ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_Attributes = FExtract_HeaderDataEx.FileAttr;
                ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_OriginalSize = FExtract_HeaderDataEx.UnpSizeHigh; ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_OriginalSize <<= 32; ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_OriginalSize += FExtract_HeaderDataEx.UnpSize;
                ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_CompressedSize = FExtract_HeaderDataEx.PackSizeHigh; ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_CompressedSize <<= 32; ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_CompressedSize += FExtract_HeaderDataEx.PackSize;
                ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_CRC = FExtract_HeaderDataEx.FileCRC;
                ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_ModifyDate = FExtract_HeaderDataEx.FileTime;
                ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_ItemName = FExtract_HeaderDataEx.FileNameW.ToString();
                FExtract_CurrentItem.RelativeName = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_ItemName;
                Result.ID = FExtract_CurrentItem.ID;
                Result.NodeData = new INodeData_RAR_ITEM();
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_Attributes = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_Attributes;
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_OriginalSize = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_OriginalSize;
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_CompressedSize = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_CompressedSize;
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_CRC = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_CRC;
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_ModifyDate = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_ModifyDate;
                ((INodeData_RAR_ITEM)Result.NodeData).RAR_ItemName = ((INodeData_RAR_ITEM)FExtract_CurrentItem.NodeData).RAR_ItemName;
                Result.RelativeName = FExtract_CurrentItem.RelativeName;

                return 1;
            }
            catch
            {
                return -1;
            }
        }
        /// <summary>Ziskanie nazvu aktualneho spracovavaneho zaznamu</summary>
        /// <returns>nazov</returns>
        public override string ExtractMode_CurrentName()
        {
            return FExtract_CurrentItem.Name;
        }
        /// <summary>Preskocenie aktualneho zaznamu z extrahovania</summary>
        public override void ExtractMode_SkipCurrentItem()
        {
            IUnrar.RARProcessFile(FExtract_ArchiveHandle, (int)IUnrar.Operation.Skip, string.Empty, string.Empty);
        }
        /// <summary>Test potreby extrahovania aktualneho zaznamu</summary>
        /// <param name="DestRelativePath">vysledna relativna cesta</param>
        /// <returns>true / false</returns>
        public override bool ExtractMode_CurrentNeedExpand(ref string DestRelativePath)
        {
            return NeedToBeExtracted(FExtract_ListOfItemsRoot, FExtract_CurrentItem.RelativeName, FExtract_ListOfItems, ref DestRelativePath); // Ma sa extrahovat?
        }
        /// <summary>Test ci zadany objekt je potrebne extrahovat</summary>
        /// <param name="pSourceRoot">spolocny root zoznamu</param>
        /// <param name="pRelativeName">nazov objektu</param>
        /// <param name="pList">zoznam objektov pre extrahovanie</param>
        /// <param name="DestRelativePath">vysledna relativna cesta</param>
        /// <returns>true / false</returns>
        public static bool NeedToBeExtracted(string pSourceRoot, string pRelativeName, System.Collections.Generic.List<string> pList, ref string DestRelativePath)
        {
            if (pList == null) return true; // Vsetky?

            foreach (string S in pList) // Prechadzam zoznam
            {
                if (pRelativeName.Length < S.Length) continue; // Test dlzky
                if (string.Compare(pRelativeName, S, false) == 0)
                {
                    if (DestRelativePath == "") return true;
                    DestRelativePath = DestRelativePath.Substring(pSourceRoot.Length);
                    return true;
                }
                string S1 = S + "\\";
                if (string.Compare(pRelativeName, 0, S1, 0, S1.Length, false) == 0)
                {
                    if (DestRelativePath == "") return true;
                    DestRelativePath = DestRelativePath.Substring(pSourceRoot.Length);
                    return true;
                }
            }
            return false;
        }

        /// <summary>Ziskanie statistickych informacii pre proces extrahovania</summary>
        /// <param name="ResultStatData">vysledna stat. data</param>
        /// <param name="pItems">zoznam poloziek pre spocitanie</param>
        /// <param name="pBreakState">premenna pre oznamenie o preruseni spracovania</param>
        /// <returns>true / false</returns>
        public override bool Run_GetExtractStatsInfo(IComputeOccupiedSpaceData ResultStatData, System.Collections.Generic.List<string> pItems = null, IThrSafeVariable pBreakState = null)
        {
            string FN = "";

            try // Test hlavicky a nacitanie dat
            {
                BeginSourceExtractMode(pItems, null);
                using (INode N = new INode())
                {
                    while (true)
                    {
                        N.Clear();
                        if (ExtractMode_GetNextSourceItem(N) != 1) break;
                        if (ExtractMode_CurrentNeedExpand(ref FN))
                        {
                            if (N.IsDirectory)
                            {
                                ResultStatData.AddDir();
                            }
                            else
                            {
                                ResultStatData.AddFile(((INodeData_RAR_ITEM)N.NodeData).RAR_OriginalSize);
                            }
                        }
                        ExtractMode_SkipCurrentItem();
                    }
                }
                CloseExtractMode();
                return true;
            }
            catch
            {
                return false; // Chyba
            }
        }
        /// <summary>Spustenie procesu kontroly archivu RAR</summary>
        /// <param name="pErrorMsg">chybova sprava</param>
        /// <param name="pProgressForm">progress formular</param>
        /// <returns>true / false</returns>
        public override bool TestArchive(out string pErrorMsg, IFileExplorer_ProgressForm_TestArchive pProgressForm = null)
        {
            pErrorMsg = ""; // Inicializacia
            FTest_ProgressForm = pProgressForm;
            if (pProgressForm != null) pProgressForm.StartArchive(FBaseArchiveFileName, "RAR");

            try
            {
                IUnrar.RAROpenArchiveDataEx Str = new IUnrar.RAROpenArchiveDataEx(); // Vyplnim strukturu
                Str.Initialize();
                Str.ArcName = FBaseArchiveFileName + "\0";
                Str.ArcNameW = FBaseArchiveFileName + "\0";
                Str.OpenMode = (uint)IUnrar.OpenMode.Extract;
                Str.CmtBuf = null;
                Str.CmtBufSize = 0;

                IntPtr ArchiveHandle = IUnrar.RAROpenArchiveEx(ref Str); // Otvorim archiv
                if (Str.OpenResult != 0) // Chyba?
                {
                    pErrorMsg = lang.NODE_LIST_RAR_ARCHIVE_TEXT_14;
                    return false;
                }

                FExtract_CallbackRoutine = new IUnrar.UNRARCallback(Test_RARCallback);
                IUnrar.RARSetCallback(ArchiveHandle, FExtract_CallbackRoutine, this.GetHashCode()); // Nastavim callback funkciu

                IUnrar.RARHeaderDataEx HeaderDataEx = new IUnrar.RARHeaderDataEx(); HeaderDataEx.Initialize(); // Inicializujem
                while (true)
                {
                    int result = IUnrar.RARReadHeaderEx(ArchiveHandle, ref HeaderDataEx);
                    if (result == (int)IUnrar.RarError.EndOfArchive) break; // Koniec archivu?
                    if (result != 0)
                    {
                        IUnrar.RARCloseArchive(ArchiveHandle); // Uzatvorim archiv
                        pErrorMsg = lang.NODE_LIST_RAR_ARCHIVE_TEXT_14;
                        return false;
                    }

                    if ((HeaderDataEx.Flags & 0x01) == 0)
                    {

                        string FN = HeaderDataEx.FileNameW.ToString();
                        int I = FN.LastIndexOf('\\');
                        if (I != -1) FN = FN.Substring(I + 1);

                        if (pProgressForm != null) // Zobrazuje sa progress?
                        {
                            if ((HeaderDataEx.Flags & 0xE0) == 0xE0) pProgressForm.AddDir();
                            else pProgressForm.StartFile(FN);
                        }

                        if (IUnrar.RARProcessFile(ArchiveHandle, (int)IUnrar.Operation.Test, string.Empty, string.Empty) != 0)
                        {
                            IUnrar.RARCloseArchive(ArchiveHandle); // Uzatvorim archiv
                            if ((pProgressForm != null) && (!pProgressForm.WaitForTerminate.BoolValue)) pErrorMsg = lang.NODE_LIST_RAR_ARCHIVE_TEXT_14;
                            return false;
                        }

                        if (pProgressForm != null) // Zobrazuje sa progress?
                        {
                            if ((HeaderDataEx.Flags & 0xE0) != 0xE0) pProgressForm.FinishFile();
                            if (pProgressForm.WaitForTerminate.BoolValue)
                            {
                                IUnrar.RARCloseArchive(ArchiveHandle); // Uzatvorim archiv
                                return false;
                            }
                        }
                    }
                }

                IUnrar.RARCloseArchive(ArchiveHandle); // Uzatvorim archiv
                return true; // Test prebehol OK
            }
            catch
            {
                pErrorMsg = string.Format(lang.NODE_LIST_TAR_ARCHIVE_TEXT_13, "RAR");
                return false; // Chyba
            }
        }
        /// <summary>Spustenie procesu extrahovania obsahu archivu</summary>
        /// <param name="pArchiveFileName">nazov archivu</param>
        /// <param name="pDestinationPath">cielove umiestnenie</param>
        /// <param name="pDetinationFolder">cielovy priecinok</param>
        /// <param name="pProgressForm">progress form</param>
        /// <returns>true / false</returns>
        public int Run_ExtractItems(System.Collections.Generic.List<string> pItems, string pDestinationPath, string pDestinationFolder, IFileExplorer_ProgressForm_ExtractArchive pProgressForm = null)
        {
            INodeList DestList;
            IConfirmationFlags Flags = new IConfirmationFlags();
            FExtract_ProgressForm = pProgressForm; // Ulozim progress form

            if (!string.IsNullOrEmpty(pDestinationFolder)) // Bude sa rozbalovat do poadresara?
            {
                while (true)
                {
                    DestList = INodeList.CreateNodeList(pDestinationPath);
                    if (DestList == null) return 1; // Chybna cielova cesta?
                    using (DestList)
                    {
                        DestList.BeginDestinationCopyMode();
                        while (true)
                        {
                            int R = DestList.CopyMode_MakeFolder(pDestinationFolder, IWin32.FILE_ATTRIBUTE_NORMAL);
                            if ((R == 0) || (R == IFileSystem.FS_ERROR_DIRECTORY_EXISTS)) break; // OK?
                            if (pProgressForm == null) return 1;

                            R = 0; // Opytam sa ci opakovat...
                            if (pProgressForm.ShowEditor_ChooseFromList(lang.FILE_EXPLORER_TEXT_24_4_28, lang.FILE_EXPLORER_TEXT_24_4_29, lang.FILE_EXPLORER_TEXT_24_4_30, ref R)) return 1;
                        }
                        break;
                    }
                }
                pDestinationPath = IFileSystem.AppendToPath(pDestinationPath, pDestinationFolder);
            }

            DestList = INodeList.CreateNodeList(pDestinationPath);
            if (DestList == null) return 1; // Chybna cielova cesta?
            using (INode N = new INode())
            {
                using (DestList)
                {
                    FExtract_DestList = DestList;
                    BeginSourceExtractMode(pItems);
                    DestList.BeginDestinationCopyMode();

                    while (true)
                    {
                        int R = ExtractMode_GetNextSourceItem(N);
                        if (R < 0)
                        {
                            return -1;
                        }
                        if (R != 1) break;

                        string DestRelativeName = N.RelativeName; // Cielova relativna cesta
                        if (!ExtractMode_CurrentNeedExpand(ref DestRelativeName)) // Je potrebne ho extrahovat?
                        {
                            ExtractMode_SkipCurrentItem(); // Preskocim ho
                            if (pProgressForm != null)
                            {
                                if (N.IsDirectory) pProgressForm.AddDir(true); else pProgressForm.AddFile(true);
                            }
                            continue;
                        }

                        if (N.IsDirectory)
                        {
                            if (RunExtractItems_Directory(this, DestList, N.RelativeName, DestRelativeName, Flags, N, pProgressForm) == -1) return 1;
                            if (pProgressForm != null) pProgressForm.AddDir();
                            ExtractMode_SkipCurrentItem(); // Preskocim ho
                        }
                        else
                        {
                            switch (Run_ExtractItems_File(DestList, N.RelativeName, DestRelativeName, Flags, N, pProgressForm))
                            {
                                case -1: return -1; // Ukoncit?
                                case 1: // Preskocit?
                                    {
                                        if (IUnrar.RARProcessFile(FExtract_ArchiveHandle, (int)IUnrar.Operation.Test, string.Empty, string.Empty) != 0) return -1;
                                    } break;
                            }
                            if (ExtractMode_WasLastItemForExtract(N.RelativeName, false)) break;
                        }

                    }
                    CloseExtractMode();
                }
            }
            return 0;
        }
        /// <summary>Extrahovanie suboru</summary>
        /// <param name="pSource">zdroj</param>
        /// <param name="pDestination">ciel</param>
        /// <param name="pRelativeName">relativna cesta</param>
        /// <returns>0 - OK, 1 - preskocene, -1 prerusene</returns>
        protected int Run_ExtractItems_File(INodeList pDestination, string pRelativeName, string pDestRelativeName, IConfirmationFlags pFlags, INode pInfoNode, IFileExplorer_ProgressForm_ExtractArchive pProgressForm = null)
        {
            if (pFlags.OpenSourceFileError != IConfirmationFlags.OPEN_SOURCE_ERROR_SKIP_ALL) pFlags.OpenSourceFileError = -1; // Inicializacia
            if (pFlags.CreateDestinationFileError != IConfirmationFlags.COPY_ERROR_SKIP_ALL) pFlags.CreateDestinationFileError = -1;
            if ((pFlags.OverwriteDestinationFile != IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL) && (pFlags.OverwriteDestinationFile != IConfirmationFlags.OVERWRITE_DESTINATION_FILE_YES_ALL)) pFlags.OverwriteDestinationFile = -1;
            if ((pFlags.OverwriteReadOnlyDestinationFile != IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL) && (pFlags.OverwriteReadOnlyDestinationFile != IConfirmationFlags.OVERWRITE_DESTINATION_FILE_YES_ALL)) pFlags.OverwriteReadOnlyDestinationFile = -1;
            if ((pFlags.OverwriteSystemDestinationFile != IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL) && (pFlags.OverwriteSystemDestinationFile != IConfirmationFlags.OVERWRITE_DESTINATION_FILE_YES_ALL)) pFlags.OverwriteSystemDestinationFile = -1;
            if (pFlags.ReadSourceFileError != IConfirmationFlags.OPEN_SOURCE_ERROR_SKIP_ALL) pFlags.ReadSourceFileError = -1;
            if (pFlags.WriteDestinationFileError != IConfirmationFlags.OPEN_SOURCE_ERROR_SKIP_ALL) pFlags.WriteDestinationFileError = -1;

            if (pProgressForm != null) pProgressForm.SetCurrentFileSize(((INodeData_RAR_ITEM)pInfoNode.NodeData).RAR_OriginalSize, ExtractMode_CurrentName());
            while (true)
            {
                if (pProgressForm != null)
                {
                    if (pProgressForm.WaitForTerminate.BoolValue)
                    {
                        return -1; // Test ukoncenia
                    }
                }

                int I = pDestRelativeName.LastIndexOf('\\');
                string FolderName = I == -1 ? "" : pDestRelativeName.Substring(0, I);
                if (FolderName != "") pDestination.CopyMode_MakeFolder(FolderName, IWin32.FILE_ATTRIBUTE_NORMAL);

                int R = pDestination.CopyMode_CreateWriteFile(pDestRelativeName, pInfoNode.Attributes, pInfoNode.DLastModify, pFlags.ForceOverwriteDestinationFile, pFlags.ForceOverwriteReadOnlyDestinationFile, pFlags.ForceOverwriteSystemDestinationFile, pFlags.ForceOverwriteSystemDestinationFile, false); // Vytvorim cielovy subor
                if (R == 0) break; // OK..

                switch (R)
                {
                    case IFileSystem.FS_ERROR_FILE_EXISTS:
                        {
                            if (pFlags.OverwriteDestinationFile == IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL)
                            {
                                if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                return 1;
                            }

                            if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_24_4_10, CopyMode_MakeSourceFullPath(pRelativeName)), lang.FILE_EXPLORER_TEXT_24_4_11, lang.FILE_EXPLORER_TEXT_24_4_12, ref pFlags.OverwriteDestinationFile)) return -1;
                            switch (pFlags.OverwriteDestinationFile)
                            {
                                case IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP:
                                case IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL:
                                    {
                                        if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                        return 1;
                                    }
                            }

                        } break;
                    case IFileSystem.FS_ERROR_READ_ONLY_ATTRIBUTE:
                        {
                            if (pFlags.OverwriteReadOnlyDestinationFile == IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL)
                            {
                                if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                return 1;
                            }
                            if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_24_4_13, CopyMode_MakeSourceFullPath(pRelativeName)), lang.FILE_EXPLORER_TEXT_24_4_14, lang.FILE_EXPLORER_TEXT_24_4_15, ref pFlags.OverwriteReadOnlyDestinationFile)) return -1;
                            switch (pFlags.OverwriteReadOnlyDestinationFile)
                            {
                                case IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP:
                                case IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL:
                                    {
                                        if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                        return 1;
                                    }
                            }
                        } break;
                    case IFileSystem.FS_ERROR_SYSTEM_ATTRIBUTE:
                    case IFileSystem.FS_ERROR_HIDDEN_ATTRIBUTE:
                        {
                            if (pFlags.OverwriteSystemDestinationFile == IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL)
                            {
                                if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                return 1;
                            }
                            if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_24_4_16, CopyMode_MakeSourceFullPath(pRelativeName)), lang.FILE_EXPLORER_TEXT_24_4_17, lang.FILE_EXPLORER_TEXT_24_4_18, ref pFlags.OverwriteSystemDestinationFile)) return -1;
                            switch (pFlags.OverwriteSystemDestinationFile)
                            {
                                case IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP:
                                case IConfirmationFlags.OVERWRITE_DESTINATION_FILE_SKIP_ALL:
                                    {
                                        if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                        return 1;
                                    }
                            }
                        } break;
                    default:
                        {
                            if (pFlags.CreateDestinationFileError == IConfirmationFlags.COPY_ERROR_SKIP_ALL)
                            {
                                if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                return 1; // Preskocit vsetky?
                            }
                            if (!pProgressForm.ShowEditor_ChooseFromList(string.Format(lang.FILE_EXPLORER_TEXT_24_4_7, CopyMode_MakeSourceFullPath(pRelativeName)), lang.FILE_EXPLORER_TEXT_24_4_8, lang.FILE_EXPLORER_TEXT_24_4_9, ref pFlags.CreateDestinationFileError)) return -1;
                            switch (pFlags.CreateDestinationFileError)
                            {
                                case IConfirmationFlags.COPY_ERROR_SKIP:
                                case IConfirmationFlags.COPY_ERROR_SKIP_ALL:
                                    {
                                        if (pProgressForm != null) pProgressForm.AddFile(true); // Zaradim subor
                                        return 1; // Preskocit vsetky?
                                    }
                            }
                        } break;
                }
            }

            if (IUnrar.RARProcessFile(FExtract_ArchiveHandle, (int)IUnrar.Operation.Test, string.Empty, string.Empty) != 0)
            {
                pDestination.CopyMode_CloseWriteFile(true); // Uzatvorim subor
                return -1;
            }

            if (pProgressForm != null) pProgressForm.AddTransferredDataSize(0); // Koniec prenosu

            pDestination.CopyMode_CloseWriteFile(false); // Uzatvorim subor
            if (pProgressForm != null) pProgressForm.AddFile(); // Zaradim subor
            return 0; // Vsetko OK
        }
    }
}
